package rightsmanagement;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;


public class RightsAdministrationService implements IRightsAdministration {
	final private static String usersPath = "D:\\Users.txt";
	private BufferedReader inStream;
	private FileOutputStream outStream;
	private HashMap<PairUserNameAndPW, UserTicket> userCache;
	private ArrayList<Integer> groups = new ArrayList<Integer>();

	private RightsAdministrationService() {
	};

	private static RightsAdministrationService rightsAdministrationService;

	public static RightsAdministrationService getRightsAdministrationService() {
		if (rightsAdministrationService == null) {
			rightsAdministrationService = new RightsAdministrationService();
		}
		return rightsAdministrationService;
	}

	@Override
	public void addUser(String userName, String password, UserGroup userGroup) {
		try {
			editUsers(userName, password, userGroup.getGroup(), Operation.ADD);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void delUser(String userName, UserGroup userGroup) {
		try {
			editUsers(userName, "", userGroup.getGroup(), Operation.DEL);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void editUser(String userName, String password, UserGroup userGroup) {
		try {
			editUsers(userName, password, userGroup.getGroup(), Operation.EDIT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private enum Operation {
		ADD, DEL, EDIT
	}

	private void initializeStreams() throws FileNotFoundException {
		inStream = new BufferedReader(new FileReader(usersPath));
	}

	private void updateCache() {
		try {
			initializeStreams();
			initGroups();
			HashMap<PairUserNameAndPW, UserTicket> p_userCache = new HashMap<PairUserNameAndPW, UserTicket>();
			String line;
			String[] parts;
			while ((line = inStream.readLine()) != null) {
				parts = line.split(";");
				if (parts.length != 3) {
					throw new RuntimeException();
				}
				Integer group = new Integer(parts[2]);
				if (!isGroup(group))
					throw new RuntimeException();
				p_userCache.put(new PairUserNameAndPW(parts[0], parts[1]),
						new UserTicket(parts[0], new UserGroup(group)));
			}
			this.userCache = p_userCache;
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public UserTicket authenticate(String user, String password) {
		updateCache();

		PairUserNameAndPW toGet = new PairUserNameAndPW(user, password);
		for (PairUserNameAndPW up : this.userCache.keySet()) {
			if (toGet.equals(up)) {
				return this.userCache.get(up);
			}
		}
		return null;
	}

	private void initGroups() {
		groups.add(1);
		groups.add(2);
	}

	private boolean isGroup(Integer i) {
		if (groups.contains(i))
			return true;
		return false;
	}

	private synchronized void editUsers(String userName, String password,
			int userGroup, Operation operation) throws IOException {
		updateCache();
		switch (operation) {
		case ADD: {
			if (!userCache.containsKey(new PairUserNameAndPW(userName, password))) {
				this.userCache.put(new PairUserNameAndPW(userName, password),
						new UserTicket(userName, new UserGroup(userGroup)));
				// FileOutputStream fO = new FileOutputStream(new
				// File(usersPath));
				FileWriter fstream = new FileWriter(usersPath);
				BufferedWriter out = new BufferedWriter(fstream);
				for (Entry<PairUserNameAndPW, UserTicket> e : userCache
						.entrySet()) {
					fstream.write(e.getKey().getUserName() + ";"
							+ e.getKey().getUserPassword() + ";"
							+ e.getValue().getUserGroup() + "\n");
				}
				out.close();
				fstream.close();
				// fstream.write
			}
			break;
		}
		case DEL: {
			this.userCache.remove(new PairUserNameAndPW(userName, password));
			break;
		}
		case EDIT: {
			this.editUsers(userName, password, 0, Operation.DEL);
			this.editUsers(userName, password, userGroup, Operation.ADD);
			break;
		}
		default:
			throw new NoSuchMethodError("Unsopported Operation");
		}
	}

}
